﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace ComicsEditor
{
    public class BalloonCircleInstrument : Instrument
    {
        public Balloon Balloon = null;

        private bool include = true;
        private Contour contour;
        private int radius = 10;
        private Point center;

        public BalloonCircleInstrument()
        {
            Order = 2;
        }

        public override void Bind(PageInfo PageInfo)
        {
            base.Bind(PageInfo);
        }

        public int Radius
        {
            get
            {
                return radius;
            }
            set
            {
                radius = value;
            }
        }

        public void Enable(bool include)
        {
            Enable();
            this.include = include;
        }

        public override void Enable()
        {
            base.Enable();
            Page.MoveObject = this;
            Show();
        }

        public override void Disable()
        {
            base.Disable();
            Page.MoveObject = null;
            Hide();
        }

        public override void Draw(Graphics Graphics)
        {
            RectangleF rectF = new RectangleF(Page.Transform(new Point(center.X - radius, center.Y - radius)), Page.Transform(new Size(radius*2, radius*2)));
            Rectangle rect = new Rectangle((int)rectF.X, (int)rectF.Y, (int)rectF.Width, (int)rectF.Height);
            Graphics.DrawEllipse(DashedLine.penEven, rect);
            Graphics.DrawEllipse(DashedLine.penOdd, rect);
        }

        public override void Move(Point newPoint, Point deltaMove)
        {
            center = newPoint;
            Page.Changed = true;
        }

        public override bool Activate(Point point, out Point offset)
        {
            offset = Point.Empty;

            List<Point> contour = new List<Point>();

            center = point;
            int x0 = point.X;
            int y0 = point.Y;

            int f = 1 - radius;
            int ddF_x = 1;
            int ddF_y = -2 * radius;
            int x = 0;
            int y = radius;

            contour.Add(new Point(x0, y0 + radius));
            contour.Add(new Point(x0, y0 - radius));
            contour.Add(new Point(x0 + radius, y0));
            contour.Add(new Point(x0 - radius, y0));

            while (x < y)
            {
                // ddF_x == 2 * x + 1;
                // ddF_y == -2 * y;
                // f == x*x + y*y - radius*radius + 2*x - y + 1;
                if (f >= 0)
                {
                    y--;
                    ddF_y += 2;
                    f += ddF_y;
                }
                x++;
                ddF_x += 2;
                f += ddF_x;
                if (x > y)
                    break;
                contour.Add(new Point(x0 + x, y0 + y));
                contour.Add(new Point(x0 - x, y0 + y));
                contour.Add(new Point(x0 + x, y0 - y));
                contour.Add(new Point(x0 - x, y0 - y));
                if (x != y)
                {
                    contour.Add(new Point(x0 + y, y0 + x));
                    contour.Add(new Point(x0 - y, y0 + x));
                    contour.Add(new Point(x0 + y, y0 - x));
                    contour.Add(new Point(x0 - y, y0 - x));
                }
            }

            contour.Sort(Compare);
            this.contour = new Contour(contour.ToArray());

            if (!Update() && include)
            {
                Balloon balloon = new Balloon(Page, new Contour(this.contour));
                pageInfo.Balloons.Add(balloon);
                if (pageInfo.BalloonCreate != null)
                    pageInfo.BalloonCreate(balloon);
            }

            return true;
        }
        
        private int Compare(Point a, Point b)
        {
            double da = Math.Atan2(a.Y - center.Y, a.X - center.X);
            double db = Math.Atan2(b.Y - center.Y, b.X - center.X);
            return Comparer<double>.Default.Compare(db, da);
        }

        public override void Drag(Point newPoint, Point offset, Point deltaActivate, Point deltaMove)
        {
            contour.Translate(deltaMove.X, deltaMove.Y);
            Update();
        }

        public bool Update()
        {
            if (include)
            {
                if (Balloon != null)
                {
                    if (Balloon.Include(contour))
                        return true;
                    return Balloon.Contains(center);
                }
            }
            else
                if (Balloon != null)
                    return Balloon.Exclude(contour);
            return false;
        }
    }
}
